package com.guyu.app.admin.biz.facade;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.util.StrUtil;
import com.alibaba.excel.EasyExcel;
import com.alibaba.excel.context.AnalysisContext;
import com.alibaba.excel.read.listener.ReadListener;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.google.common.collect.Sets;
import com.guyu.app.admin.controller.request.DistrictImportReq;
import com.guyu.app.admin.controller.response.DistrictCityRsp;
import com.guyu.app.admin.controller.response.DistrictRsp;
import com.guyu.app.admin.pojo.converter.DistrictConverter;
import com.guyu.app.common.biz.service.DistrictService;
import com.guyu.app.common.constant.DistrictConstants;
import com.guyu.app.common.enums.DistrictLevelEnum;
import com.guyu.app.common.enums.DistrictSubdistrictEnum;
import com.guyu.app.common.pojo.domain.ds.DistrictDO;
import com.guyu.app.common.remote.GaodeRemote;
import com.guyu.app.common.remote.response.GaoDeDistrictRsp;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;

import java.time.LocalDateTime;
import java.util.*;
import java.util.stream.Collectors;

@Slf4j
@Service
@RequiredArgsConstructor
public class DistrictFacade {

    private final DistrictService districtService;
    private final GaodeRemote gaodeRemote;

    /**
     * 批量导入行政区
     */
    @Async
    public void importDistricts(MultipartFile file, String version) throws Exception {
        EasyExcel.read(file.getInputStream(), DistrictImportReq.class, new ReadListener<DistrictImportReq>() {
            @Override
            public void invoke(DistrictImportReq data, AnalysisContext analysisContext) {
                String path = DistrictConstants.CHINA_AD_CODE;
                //省
                DistrictDO province = DistrictConverter.init(data.getName_prov(), data.getCode_prov(),
                        DistrictLevelEnum.PROVINCE, DistrictConstants.CHINA_AD_CODE, path, version);
                if (Objects.isNull(province)) {
                    return;
                }
                //市
                path = path + DistrictConstants.PATH_SPLIT + province.getAdcode();
                DistrictDO city =
                        DistrictConverter.init(data.getName_city(), data.getCode_city(), DistrictLevelEnum.CITY, province.getAdcode(), path, version);
                if (Objects.isNull(city)) {
                    return;
                }
                //区
                path = path + DistrictConstants.PATH_SPLIT + city.getAdcode();
                DistrictDO district =
                        DistrictConverter.init(data.getName_coun(), data.getCode_coun(), DistrictLevelEnum.DISTRICT, city.getAdcode(), path, version);
                if (Objects.isNull(district)) {
                    return;
                }
                //街道
                path = path + DistrictConstants.PATH_SPLIT + district.getAdcode();
                DistrictDO street =
                        DistrictConverter.init(data.getName_town(), data.getCode_town(), DistrictLevelEnum.STREET, district.getAdcode(), path, version);
                if (Objects.isNull(street)) {
                    return;
                }
                districtService.insertOrUpdate(province);
                if (!Objects.equals(province.getAdcode(), city.getAdcode())) {
                    districtService.insertOrUpdate(city);
                }
                if (!Objects.equals(city.getAdcode(), district.getAdcode())) {
                    districtService.insertOrUpdate(district);
                }
                if (!Objects.equals(district.getAdcode(), street.getAdcode())) {
                    districtService.insertOrUpdate(street);
                }
            }

            @Override
            public void doAfterAllAnalysed(AnalysisContext analysisContext) {
                log.info("所有数据解析完成！count:{}", analysisContext.getTotalCount());
            }
        }).sheet().doRead();
    }

    /**
     * 行政区查询
     *
     * @param keywords    规则：只支持单个关键词语搜索关键词支持：行政区名称、adcode
     * @param subdistrict 设置显示下级行政区级数（0不返回下级行政区,1返回下一级行政区,2返回下两级行政区,3返回下三级行政区）
     */
    public List<DistrictRsp> district(String keywords, Integer subdistrict) {
        List<DistrictDO> list = Lists.newArrayList();
        if (StringUtils.isBlank(keywords)) {
            DistrictDO districtDO = districtService.findByAdcode(DistrictConstants.CHINA_AD_CODE);
            list.add(districtDO);
        } else if (StrUtil.isNumeric(keywords)) {
            DistrictDO districtDO = districtService.findByAdcode(keywords);
            list.add(districtDO);
        } else {
            List<DistrictDO> districtDOList = districtService.findByNameLike(keywords);
            if (CollectionUtil.isNotEmpty(districtDOList)) {
                list.addAll(districtDOList);
            }
        }
        List<DistrictRsp> reList = DistrictConverter.toRspList(list);
        buildChildren(reList, subdistrict, DistrictSubdistrictEnum.NONE.getCode());
        return reList;
    }

    private void buildChildren(List<DistrictRsp> list, Integer subdistrict, Integer level) {
        if (CollectionUtil.isEmpty(list)) {
            return;
        }
        if (Objects.isNull(subdistrict) || subdistrict <= level) {
            return;
        }
        Set<String> adCodeSet = list.stream().map(DistrictRsp::getAdcode).collect(Collectors.toSet());
        List<DistrictDO> districtDOList = districtService.findByParentCodeIn(adCodeSet);
        Map<String, List<DistrictDO>> districtDOMap =
                districtDOList.stream().collect(Collectors.groupingBy(DistrictDO::getParentCode));
        for (DistrictRsp districtRsp : list) {
            List<DistrictDO> subList = districtDOMap.get(districtRsp.getAdcode());
            List<DistrictRsp> subRspList = DistrictConverter.toRspList(subList);
            districtRsp.getDistricts().addAll(subRspList);
            buildChildren(subRspList, subdistrict, level + 1);
        }
    }

    /**
     * 同步行政区
     */
    @Async
    public void syncDistrictByGaode(String adcode) {
        List<DistrictDO> list = Lists.newArrayList();
        if (Objects.isNull(adcode)) {
            //查询全部
            list = districtService.findByParentCode(DistrictConstants.CHINA_AD_CODE);
        } else {
            //单个查询
            DistrictDO districtDO = districtService.findByAdcode(adcode);
            list.add(districtDO);
        }
        //远程调用高德查询
        for (DistrictDO districtDO : list) {
            List<GaoDeDistrictRsp> districts = gaodeRemote.district(districtDO.getAdcode(), DistrictSubdistrictEnum.THREE.getCode());
            updateDistrictDO(districts);
        }
    }

    private void updateDistrictDO(List<GaoDeDistrictRsp> list) {
        if (CollectionUtil.isEmpty(list)) {
            return;
        }
        for (GaoDeDistrictRsp district : list) {
            int districtLevel = GaoDeDistrictRsp.getDistrictLevel(district.getLevel());
            DistrictDO districtDO = null;
            if (Objects.equals(districtLevel, DistrictLevelEnum.STREET.getCode())) {
                //街道没有独有的 adcode，均继承父类（区县）的 adcode,需要根据名称查询
                districtDO = districtService.findByParentCodeAndName(district.getAdcode(), district.getName());
            } else {
                districtDO = districtService.findByAdcode(district.getAdcode());
            }
            if (Objects.isNull(districtDO)) {
                continue;
            }

//            TinyPinyinEngine engine = TinyPinyinUtil.getEngine();
//            districtDO.setName(district.getName());
//            districtDO.setPinyin(engine.getFirstLetter(districtDO.getName(), ""));

            districtDO.setCenter(district.getCenter());
            districtDO.setCityCode(district.getCitycode());
            districtDO.setUpdateTime(LocalDateTime.now());
            districtService.updateById(districtDO);
            updateDistrictDO(district.getDistricts());
        }
    }


    public List<DistrictCityRsp> initial(Integer subdistrict) {
        Set<Integer> levels = Sets.newHashSet(DistrictLevelEnum.CITY.getCode());
        if (Objects.equals(subdistrict, DistrictLevelEnum.DISTRICT.getCode())) {
            levels.add(DistrictLevelEnum.DISTRICT.getCode());
        }
        List<DistrictDO> list = districtService.findByLevelIn(levels);
        Map<String, List<DistrictRsp>> map = Maps.newHashMap();
        for (DistrictDO districtDO : list) {
            DistrictRsp districtRsp = DistrictConverter.toRsp(districtDO);
            String initial = StrUtil.subPre(districtDO.getPinyin(), 1).toUpperCase(Locale.ROOT);
            List<DistrictRsp> subList = map.getOrDefault(initial, Lists.newArrayList());
            subList.add(districtRsp);
            map.put(initial, subList);
        }
        List<DistrictCityRsp> reList = Lists.newArrayList();
        map.forEach((k, v) -> {
            DistrictCityRsp districtCityRsp = new DistrictCityRsp();
            districtCityRsp.setInitial(k);
            districtCityRsp.setDistricts(v);
            reList.add(districtCityRsp);
        });

        return reList.stream().sorted(Comparator.comparing(DistrictCityRsp::getInitial)).collect(Collectors.toList());
    }

    public List<DistrictRsp> getDistrictByLevel(Integer level) {
        List<DistrictDO> list = districtService.findByLevelIn(Lists.newArrayList(level));
        return list.stream().sorted(Comparator.comparing(DistrictDO::getAdcode)).map(DistrictConverter::toRsp).collect(Collectors.toList());
    }
}
